package com.kning.mastermind;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * MastermindApplication
 *
 * @author ning
 **/
public class MastermindApplication {
    // 候选结果集 - 可能的答案
    private static HashSet<Element4b> resultSet = new HashSet<>(1 << 10);
    // 每步选择的历史记录
    private static final LinkedList<Element4b> choiceHistory = new LinkedList<>();

    // 尝试次数
    private static int tryTime = 0;

    // 目标元素
    private static Element4b TAG_RESULT = new Element4b(1234);

    public static void main(String[] args) {
        long beginTime = System.currentTimeMillis();
        // 用户输入 todo
        TAG_RESULT = new Element4b(1234);
        System.out.println("设置目标TAG_RESULT: " + TAG_RESULT);

        // 校验用户输入合法性
        if (!MastermindUtils.MastermindCheckForE4b(TAG_RESULT)) {
            System.out.println("非法输入" + TAG_RESULT);
        }

        // 初始化结果集
        initProbalySetForE4b();
        System.out.println("初始化结果集, SetSize: " + resultSet.size());

        do {
            System.out.println("=====================");
            Element4b element4b = processSolutionParallel();
            System.out.printf("第%2d次尝试, 猜测%d\n", tryTime, element4b.getNumber());
            // 获得结果
            int guessResult = MastermindUtils.MastermindMatchForE4b(element4b, TAG_RESULT);
            System.out.printf("第%2d次尝试, 猜测结果为%s\n", tryTime, MatchResultEnum.getCode(guessResult));

            // 更新结果集
            resultSet = MastermindUtils.getNewResultSetE4b(resultSet, element4b, guessResult);
            System.out.printf("第%2d次尝试, 猜测后结果集规模为%d\n", tryTime, resultSet.size());

            // 判断结束条件
            if (resultSet.size() == 1) {
                System.out.println("猜测结果: " + resultSet);
                break;
            }

        } while (tryTime < 10);

        System.out.println("耗时: " + (System.currentTimeMillis() - beginTime));

    }

    private static Element4b processSolution() {
        if (tryTime++ == 0) {
            return new Element4b(1234);
        }
        // 优先队列 - 大顶堆 - 容量 1 << 2
        PriorityQueue<AvgReducetion> avgReducetionPriorityQueue =
                new PriorityQueue<>(1 << 2, (o1, o2) -> o2.getAverageReduction() - o1.getAverageReduction());

        // 假设猜测某个元素 guess
        for (Element4b guess : resultSet) {
            // 猜测 guess 时的结果集规模平均缩减量
            int averageReduction = 0;

            // 假设结果是某个元素 hypothesisResult
            for (Element4b hypothesisResult : resultSet) {
                // 获取匹配结果
                int matchResult = MastermindUtils.MastermindMatchForE4b(guess, hypothesisResult);

                // 获取假设猜测 guess 的结果集缩减量
                HashSet<Element4b> newResultSet = MastermindUtils.getNewResultSetE4b(resultSet, guess, matchResult);

                // 如果本次猜测 guess，结果为 hypothesisResult 时的结果集缩减量
                int reduction = resultSet.size() - newResultSet.size();
                averageReduction += reduction;
            }
            AvgReducetion avgReducetion = new AvgReducetion(guess, averageReduction);
            avgReducetionPriorityQueue.add(avgReducetion);
        }

        // 选择缩减量最大的猜测方式
        AvgReducetion maxAvgReduceGuess = avgReducetionPriorityQueue.peek();
        System.out.println("maxAvgReduceGuess" + maxAvgReduceGuess);

        return maxAvgReduceGuess.getElement4b();
    }

    private static Element4b processSolutionParallel() {
        if (tryTime++ == 0) {
            return new Element4b(1234);
        }
        // 优先队列 - 大顶堆 - 容量 1 << 2
        PriorityBlockingQueue<AvgReducetion> avgReducetionPriorityQueue =
                new PriorityBlockingQueue<>(1 << 2, (o1, o2) -> o2.getAverageReduction() - o1.getAverageReduction());

        // 假设猜测某个元素 guess
        resultSet.parallelStream().forEach(guess -> {
            // 猜测 guess 时的结果集规模平均缩减量
            int averageReduction = 0;

            // 假设结果是某个元素 hypothesisResult
            for (Element4b hypothesisResult : resultSet) {
                // 获取匹配结果
                int matchResult = MastermindUtils.concurrentMatchForE4b(guess, hypothesisResult);

                // 获取假设猜测 guess 的结果集缩减量
                HashSet<Element4b> newResultSet = MastermindUtils.concurrentGetNewResultSetE4b(resultSet, guess, matchResult);

                // 如果本次猜测 guess，结果为 hypothesisResult 时的结果集缩减量
                int reduction = resultSet.size() - newResultSet.size();
                averageReduction += reduction;
            }
            AvgReducetion avgReducetion = new AvgReducetion(guess, averageReduction);
            avgReducetionPriorityQueue.add(avgReducetion);
        });

        // 选择缩减量最大的猜测方式
        AvgReducetion maxAvgReduceGuess = avgReducetionPriorityQueue.peek();
        System.out.println("maxAvgReduceGuess: " + maxAvgReduceGuess +
                " avg: " + maxAvgReduceGuess.getAverageReduction().doubleValue() / resultSet.size());

        return maxAvgReduceGuess.getElement4b();
    }

    private static void initProbalySetForE4b() {
        for (int i = 123; i < 9877; i++) {
            // 构造候选元素
            Element4b element4b = new Element4b(i);
            // 合法校验
            if (MastermindUtils.MastermindCheckForE4b(element4b)) {
                resultSet.add(element4b);
            }
        }
    }


}
